home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1996 January / macformat-033.iso / mac / Shareware City / Graphics / GifScan 1.6 / Sources / GifScan.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-10-09  |  19.0 KB  |  918 lines  |  [TEXT/MMCC]

  1. #include "GifScan.h"
  2. #include "Prefs.h"
  3. #include "DSUtils.h"
  4.  
  5. // GIFSCAN - scans through a GIF file and reports all parameters 
  6.  
  7. #include <stdio.h>
  8.  
  9. enum GIFErrors { kCorruptMessage = 7 };
  10.  
  11. extern     thePrefsHandle    gPrefs;
  12. extern    Boolean            gCmdHeldDown;
  13.  
  14. static Boolean        showAll, isGIF;
  15. static char            *textBuffer;
  16. static long            bufCounter;
  17.  
  18. // Function prototypes 
  19. int        UnixMain(int, char **);
  20. void    ColorMap(int, FILE *, int);
  21. void    ExtensionInfo(FILE *);
  22. void    CheckUnexpected(int *, int);
  23. void    GetImageInfo(FILE *, int, int);
  24. unsigned int GetBytes(FILE *);
  25.  
  26. #define kTempBufferSize        6000L
  27. #define MAX                 255
  28.  
  29. //**********************************************************************
  30. // MAIN - the main routine reads the GIF file for the global GIF        
  31. //        information which it displays to the user's screen.  This        
  32. //        routine also determines which subroutine to call and which        
  33. //        information to process.                                                
  34. //**********************************************************************
  35.  
  36. #define DECIMAL 1
  37. #define PERCENT 2
  38. #define HEXIDEC 3
  39.  
  40. static void CopyHTMLTagToClipboard(void)
  41. {
  42.     // Find the tag by scanning through the textbuffer...
  43.     short    i;
  44.     short    start, end;
  45.     long    err;
  46.  
  47.     i = 1;
  48.     while ( textBuffer[i] != '<' )
  49.     {    
  50.         i++;
  51.     }
  52.     start = i;
  53.     while ( textBuffer[i] != '>' )
  54.     {
  55.         i++;
  56.     }
  57.     end  = i;
  58.     
  59.     ZeroScrap();
  60.     err = PutScrap(1 + end - start, 'TEXT', &textBuffer[start]);
  61. }
  62.  
  63. static void CreateBuffer(void)
  64. {
  65.     textBuffer = NewPtr(kTempBufferSize);    // 6000 bytes should be enough....
  66.     bufCounter = 0L;
  67. }
  68.  
  69. static void DestroyBufferAndCopy(void)
  70. {    
  71.     TEHandle        te;
  72.     static short    numLines;
  73.     
  74.     if ( (*gPrefs)->copy && isGIF ) CopyHTMLTagToClipboard();
  75.     
  76.     te = ((DocumentPeek)gOutWindow)->docTE;
  77.     numLines = (*te)->nLines;
  78.  
  79.     if ( bufCounter + (*te)->teLength > kMaxTELength )
  80.     {
  81.         // exceeded TE 32k limit -> remove data from the text
  82.         TESetSelect(0L, kTempBufferSize, te);
  83.         TEDelete(te);
  84.     }
  85.     TESetSelect(kMaxTELength, kMaxTELength, te);    // Insert at end of text
  86.     TEInsert(textBuffer+1, bufCounter, te);            // Avoid garbage at 0
  87.     
  88.     // Scroll down to show the last item opened
  89.     numLines = (*te)->nLines - numLines;
  90.     TEScroll(0, -numLines * (*te)->lineHeight, te);
  91.     AdjustScrollbars(gOutWindow, false);
  92.     AdjustTE(gOutWindow);
  93.     
  94.     // Dispose of the buffer
  95.     DisposePtr(textBuffer);
  96. }
  97.  
  98. // Inspired by Paul Dubois TransDisplay
  99. static void DisplayText(Ptr theText, long len)
  100. {
  101.     BlockMoveData(theText, textBuffer + bufCounter + 1, len);
  102.     bufCounter += len;
  103.     // Originally, this called TEInsert immediately, way too slow
  104. }
  105.  
  106. static void DisplayString (StringPtr str)
  107. {
  108.     DisplayText ((Ptr) (str+1), (long) str[0]);
  109. }
  110.  
  111. static void DisplayCString (char *str)
  112. {
  113.     long    len = 0;
  114.     char    *s;
  115.  
  116.     for (s = str; *s != '\0'; s++)
  117.         ++len;
  118.     DisplayText ((Ptr) str, len);
  119. }
  120.  
  121. static void DisplayChar (short c)
  122. {
  123.     char    ch = c;
  124.  
  125.     DisplayText (&ch, 1L);
  126. }
  127.  
  128. static void DisplayLong (long l, Boolean table)
  129. {
  130.     Str255        s, space;
  131.  
  132.     NumToString (l, s);
  133.     if ( table )
  134.     {
  135.         // Textedit does not support tabs so must come up with something else
  136.         // to make a table look like something...
  137.         // This is very custom to this application
  138.         if ( l < 10 )
  139.         {
  140.             pcpy(space, "\p ");
  141.             pcat(space, s);
  142.             pcpy(s, space);
  143.         }
  144.         if ( l < 100 )
  145.         {
  146.             pcpy(space, "\p ");
  147.             pcat(space, s);
  148.             pcpy(s, space);
  149.         }
  150.     }
  151.     DisplayString (s);
  152. }
  153.  
  154. static void DisplayShort (short i, Boolean table)
  155. {
  156.     DisplayLong ((long) i, table);
  157. }
  158.  
  159. static void DisplayLn (void)
  160. {
  161.     DisplayChar ('\r');
  162. }
  163.  
  164. static void HexByte (short value)    // should be 0..15 
  165. {
  166.     DisplayChar ((char) (value + (value < 10 ? '0' : 'A' - 10)));
  167. }
  168.  
  169. static void DisplayHexChar (short c)
  170. {
  171.     HexByte ((short) (c >> 4) & 0x0f);
  172.     HexByte ((short) c & 0x0f);
  173. }
  174.  
  175. // From MoreFiles 1.3
  176. static OSErr GetFilenameFromPathname(ConstStr255Param pathname, Str255 filename)
  177. {
  178.     short    index;
  179.     short    nameEnd;
  180.  
  181.     filename[0] = 0;
  182.  
  183.     if ( pathname == nil ) return ( notAFileErr );
  184.     
  185.     index = pathname[0];
  186.     
  187.     if ( index == 0 ) return ( notAFileErr );
  188.     
  189.     if ( pathname[index] == ':' )
  190.         --index;
  191.  
  192.     nameEnd = index;
  193.  
  194.     if ( pathname[index] == ':' ) return ( notAFileErr );
  195.         
  196.     while ( (index != 0) && (pathname[index] != ':') )
  197.     {
  198.         --index;
  199.     }
  200.     
  201.     if ( (index == 0) && (pathname[pathname[0]] == ':') )
  202.         return ( notAFileErr );
  203.     
  204.     filename[0] = (char)(nameEnd - index);
  205.     BlockMoveData(&pathname[index+1], &filename[1], nameEnd - index);
  206.     return ( noErr );
  207. }
  208.  
  209. int UnixMain(int argc, char **argv)
  210. {
  211.     char version[7];
  212.     
  213.     Str255        fileName;
  214.  
  215.     int    byte1;
  216.     int    byte2;
  217.     int    byte3;
  218.     int    colorResolution;
  219.     int    unexpected;
  220.     int    imageCount;
  221.     int    bitsPerPix;
  222.     int    bitsToUse;
  223.     int    colors;
  224.     int    i, n;
  225.     int    globl;
  226.     int    endOfGifFound;
  227.     int    colorStyle;
  228.  
  229.     unsigned int    width;
  230.     unsigned int    height;
  231.     
  232.     FILE *in;
  233.     
  234.     // Start of Processing 
  235.     SetCursor(*GetCursor(watchCursor));
  236.     colorStyle = 0;
  237.     
  238.     if ( (*gPrefs)->hexadecimal ) colorStyle = HEXIDEC;
  239.     if ( (*gPrefs)->decimal ) colorStyle = DECIMAL;
  240.     if ( (*gPrefs)->percentages ) colorStyle = PERCENT;
  241.     
  242.     if ( (*gPrefs)->forget && gCmdHeldDown )
  243.         showAll = true;
  244.     else if ( (*gPrefs)->forget && !gCmdHeldDown )
  245.         showAll = false;
  246.     else if ( !(*gPrefs)->forget && gCmdHeldDown )
  247.         showAll = false;
  248.     else
  249.         showAll = true;
  250.     
  251.     for ( n = 1; n < argc; n++ )
  252.     {
  253.         in = fopen(argv[n], "rb");
  254.  
  255.         imageCount = 0;
  256.         endOfGifFound = 0;
  257.         unexpected = 0;
  258.  
  259.         CreateBuffer();
  260.  
  261.         // Print name of the inputfile
  262.         if ( showAll )
  263.         {
  264.             DisplayString("\pFilename: ");
  265.             DisplayCString(argv[n]);
  266.             DisplayLn();
  267.         }
  268.         
  269.         // get version from file 
  270.         if ( ( version[0] = getc(in) ) == 0x47 ) 
  271.         {
  272.             isGIF = true;
  273.             
  274.             for (i = 1; (i < 6); i++)
  275.                 version[i] = getc(in);
  276.             version[6] = '\0';
  277.             if ( showAll )
  278.             {
  279.                 DisplayString("\pGIF Version: ");
  280.                 DisplayCString(version);
  281.                 DisplayLn();
  282.             }
  283.             
  284.             // determine image width 
  285.             width = GetBytes(in);
  286.         
  287.             // determine image height 
  288.             height = GetBytes(in);
  289.             
  290.             if ( showAll )
  291.             {
  292.                 // General 
  293.                 DisplayString("\pImage Height: ");
  294.                 DisplayShort(height, false);
  295.                 DisplayString("\p   Image Width: ");
  296.                 DisplayShort(width, false);
  297.                 DisplayLn(); DisplayLn();
  298.             }    
  299.             
  300.             // HTML specification, show always 
  301.             DisplayString("\p<IMG SRC=\"");
  302.             if ( (*gPrefs)->fullPath )
  303.             {
  304.                 DisplayCString(argv[n]);
  305.             }
  306.             else
  307.             {    
  308.                 c2p(argv[n]);
  309.                 GetFilenameFromPathname((ConstStr255Param)argv[n], fileName);
  310.                 DisplayString(fileName);
  311.                 p2c((StringPtr)argv[n]);
  312.             }
  313.             DisplayString("\p\" ");
  314.             DisplayString("\pALT=\"\"");
  315.             DisplayString("\p HEIGHT=");
  316.             DisplayShort(height, false);
  317.             DisplayString("\p WIDTH=");
  318.             DisplayShort(width, false);
  319.             DisplayString("\p>");
  320.             
  321.             if ( showAll)
  322.             {
  323.                 DisplayLn(); DisplayLn();
  324.             }
  325.         
  326.             // check for a Global Map 
  327.             byte1 = getc(in);
  328.             byte2 = byte1 & 0x80;
  329.             if ( byte2 == 0x80 ) 
  330.             {
  331.                 if ( showAll )
  332.                 {
  333.                     DisplayString("\pGlobal Color Map: Yes");
  334.                     DisplayLn();
  335.                 }
  336.                 globl = 1;
  337.             }
  338.             else 
  339.             {
  340.                 if ( showAll )
  341.                 {
  342.                     DisplayString("\pGlobal Color Map: No");
  343.                     DisplayLn();
  344.                 }
  345.                 globl = 0;
  346.             }
  347.         
  348.             // Check for the 0 bit 
  349.             
  350.             byte2 = byte1 & 0x08;
  351.             if ( byte2 != 0 )
  352.             {
  353.                 if ( showAll ) 
  354.                 {
  355.                     DisplayString("\p? -- Reserved zero bit is not zero.");
  356.                     DisplayLn();
  357.                 }
  358.             }
  359.             
  360.             // determine the color resolution 
  361.             byte2 = byte1 & 0x70;
  362.             colorResolution = byte2 >> 4;
  363.         
  364.             // get the background index 
  365.             byte3 = getc(in);
  366.             if ( showAll ) 
  367.             {
  368.                 DisplayString("\pColor res: ");
  369.                 DisplayShort(++colorResolution, false);
  370.                 DisplayString("\p    Background index: ");
  371.                 DisplayLong(byte3, false);
  372.                 DisplayLn(); DisplayLn();
  373.             }
  374.             
  375.             // determine the bits per pixel 
  376.             bitsPerPix = byte1 & 0x07;
  377.             bitsPerPix++;
  378.             bitsToUse = bitsPerPix;
  379.         
  380.             // determine # of colors in global map 
  381.             colors = 1 << bitsPerPix;
  382.             if ( showAll )
  383.             {    
  384.                 DisplayString("\pBits per pixel: ");
  385.                 DisplayShort(bitsPerPix, false);
  386.                 DisplayString("\p    Colors: ");
  387.                 DisplayShort(colors, false);
  388.                 DisplayLn();
  389.             }
  390.             
  391.             // check for the 0 byte 
  392.             byte1 = getc(in);
  393.             if ( byte1 != 0 )
  394.             {
  395.                 if ( showAll ) 
  396.                 {
  397.                     DisplayString("\p? -- Reserved byte after Background index is not zero.");
  398.                     DisplayLn();
  399.                 }
  400.             }
  401.             
  402.             ColorMap (colorStyle, in, colors);
  403.                 
  404.             // check for the zero byte count, a new image, or the end marker for the gif file 
  405.             while ( ( byte1 = getc(in) ) != EOF ) 
  406.             {
  407.                 if ( byte1 == ',' ) 
  408.                 {
  409.                     imageCount++;
  410.                     if (unexpected != 0) CheckUnexpected(&unexpected, imageCount);
  411.                     GetImageInfo(in, bitsToUse, colorStyle);
  412.                 }
  413.                 else if (byte1 == '!')
  414.                     ExtensionInfo (in);
  415.                 else if (byte1 == ';') 
  416.                 {
  417.                     if (unexpected != 0) CheckUnexpected(&unexpected, -1);
  418.                     endOfGifFound = 1;
  419.                 }
  420.                 else
  421.                     unexpected++;
  422.             }
  423.         
  424.             // EOF has been reached - check last bytes read 
  425.             if (endOfGifFound == 0)
  426.             {
  427.                 if (showAll) 
  428.                 {
  429.                     DisplayString("\p? -- GIF file terminator ';' was not found.");
  430.                     DisplayLn();
  431.                 }
  432.             }
  433.             else if (unexpected != 0) 
  434.                 CheckUnexpected(&unexpected, -2);
  435.         }
  436.         else 
  437.         {
  438.             isGIF = false;
  439.             if ( !showAll )
  440.             {
  441.                 DisplayString("\pFilename: ");
  442.                 DisplayCString(argv[n]);
  443.                 DisplayLn();
  444.             }
  445.             DisplayString("\p...Is probably NOT a GIF file!!!");
  446.             DisplayLn();
  447.             if ( showAll ) DisplayLn();
  448.         }
  449.         clearerr(in);
  450.         fclose(in);
  451.         
  452.         if ( showAll )
  453.         {
  454.             DisplayString("\p-----------------------------------------");
  455.             DisplayLn(); DisplayLn();
  456.         }
  457.         DestroyBufferAndCopy();
  458.     }
  459.     
  460.     SetCursor(&qd.arrow);
  461.     // Reset this global to false 
  462.     gCmdHeldDown = false;
  463. }
  464.  
  465. //**********************************************************************
  466. // COLORMAP - reads color information in from the GIF file and displays 
  467. //            it in a user selected method.  This display may be in :       
  468. //            hexidecimal (default), percentage, or decimal.  User          
  469. //            selects output method by placing a switch (-d, -p, -h)        
  470. //            between the program name and GIF filename at request time.    
  471. //**********************************************************************
  472.  
  473. void ColorMap(int out, FILE *dev, int times)
  474. {
  475.     unsigned int    red;
  476.     unsigned int    green;
  477.     unsigned int    blue;
  478.  
  479.     int    printCount;
  480.     int    i;
  481.  
  482.     // Start of procedure 
  483.     
  484.     if ( (*gPrefs)->showColors || gCmdHeldDown ) 
  485.     {
  486.         DisplayLn();
  487.         if (out == DECIMAL)
  488.         {
  489.             if ( showAll )
  490.                 DisplayString("\pColor definitions in decimal (index # R, G, B)");
  491.         }
  492.     
  493.         if (out == PERCENT)
  494.         {
  495.             if ( showAll )
  496.                 DisplayString("\pColor definitions by percentage (index # R, G, B)");
  497.         }
  498.     
  499.         if (out == HEXIDEC)
  500.         {
  501.             if ( showAll )
  502.                 DisplayString("\pColor definitions by hexidecimal (index # R, G, B)");
  503.         }
  504.         DisplayLn();
  505.     
  506.         // read and print the color definitions 
  507.         printCount = 0;
  508.     
  509.         for (i = 0; (i < times); i++) 
  510.         {
  511.             red = getc(dev);
  512.             green = getc(dev);
  513.             blue = getc(dev);
  514.         
  515.             switch (out) 
  516.             {
  517.                 case DECIMAL :
  518.                     if ( showAll ) 
  519.                     {    
  520.                         DisplayShort(i, true);
  521.                         DisplayString("\p - ");
  522.                         DisplayShort(red, true);
  523.                         DisplayString("\p ");
  524.                         DisplayShort(green, true);
  525.                         DisplayString("\p ");
  526.                         DisplayShort(blue, true);
  527.                         DisplayString("\p   ");
  528.                     }
  529.                     break;
  530.                     
  531.                 case PERCENT :
  532.                     red = (red * 100) / MAX;
  533.                     green = (green * 100) / MAX;
  534.                     blue = (blue * 100) / MAX;
  535.                     if ( showAll ) 
  536.                     {    
  537.                         DisplayShort(i, true);
  538.                         DisplayString("\p - ");
  539.                         DisplayShort(red, true);
  540.                         DisplayString("\p ");
  541.                         DisplayShort(green, true);
  542.                         DisplayString("\p ");
  543.                         DisplayShort(blue, true);
  544.                         DisplayString("\p   ");
  545.                     }
  546.                     break;
  547.                     
  548.                 case HEXIDEC :
  549.                     if ( showAll ) 
  550.                     {    
  551.                         DisplayShort(i, true);
  552.                         DisplayString("\p - ");
  553.                         DisplayHexChar(red);
  554.                         DisplayString("\p ");
  555.                         DisplayHexChar(green);
  556.                         DisplayString("\p ");
  557.                         DisplayHexChar(blue);
  558.                         DisplayString("\p   ");
  559.                     }
  560.                     break;
  561.             }
  562.             
  563.             printCount++;
  564.             if (printCount == 4) 
  565.             {
  566.                 if ( showAll ) DisplayLn();
  567.                 printCount = 0;
  568.             }
  569.         }
  570.             
  571.         if ((times % 4) != 0)
  572.             if ( showAll ) DisplayLn();
  573.     }
  574.     else
  575.     {
  576.         // No feedback to screen 
  577.         printCount = 0;
  578.         for (i = 0; (i < times); i++) 
  579.         {
  580.             red = getc(dev);
  581.             green = getc(dev);
  582.             blue = getc(dev);
  583.             printCount++;
  584.             if (printCount == 4) printCount = 0;
  585.         }
  586.     }
  587. }
  588.  
  589. //**********************************************************************
  590. // GETBYTES - routine to retrieve two bytes of information from the GIF 
  591. //            file and then shift them into correct byte order.  The        
  592. //            information is stored in Least Significant Byte order.        
  593. //**********************************************************************
  594.  
  595. unsigned int GetBytes(FILE *dev)
  596. {
  597.     int    byte1;
  598.     int    byte2;
  599.     int    result;
  600.  
  601.     // read bytes and shift over 
  602.     byte1 = getc(dev);
  603.     byte2 = getc(dev);
  604.  
  605.     result = (byte2 << 8) | byte1;
  606.  
  607.     return result;
  608. }
  609.  
  610.  
  611. //**********************************************************************
  612. // IMAGEINF - routine to read the GIF image information and display it     
  613. //            to the user's screen in an orderly fashion.  If there are     
  614. //            multiple images then IMAGEINF will be called to display      
  615. //            multiple screens.                                            
  616. //**********************************************************************
  617.  
  618. void GetImageInfo(FILE *dev, int bitsToUse, int colorStyle)
  619. {
  620.     int    byte1;
  621.     int    byte2;
  622.     int    imageLeft;
  623.     int    imageTop;
  624.     int    dataByteCount;
  625.     int    bitsPerPix;
  626.     int    colors;
  627.     int    i;
  628.     int    local;
  629.  
  630.     unsigned int    width;
  631.     unsigned int    height;
  632.  
  633.     unsigned long bytetot;
  634.     unsigned long possbytes;
  635.  
  636.     // determine the image left value 
  637.     imageLeft = GetBytes(dev);
  638.  
  639.     // determine the image top value 
  640.     imageTop = GetBytes(dev);
  641.  
  642.     // determine the image width 
  643.     width = GetBytes(dev);
  644.  
  645.     // determine the image height 
  646.     height = GetBytes(dev);
  647.  
  648.     // check for interlaced image 
  649.     byte1 = getc(dev);
  650.     byte2 = byte1 & 0x40;
  651.     if ( byte2 == 0x40 )
  652.     {
  653.         if (showAll) 
  654.         {
  655.             DisplayLn();
  656.             DisplayString("\pInterlaced: Yes");
  657.             DisplayLn();
  658.         }
  659.     }
  660.     else
  661.     {
  662.         if (showAll) 
  663.         {
  664.             DisplayLn();
  665.             DisplayString("\pInterlaced: No");
  666.             DisplayLn();
  667.         }
  668.     }
  669.  
  670.     // check for a local map 
  671.     byte2 = byte1 & 0x80;
  672.     if ( byte2 == 0x80 ) 
  673.     {
  674.         local = 1;
  675.         if (showAll) 
  676.         {
  677.             DisplayString("\pLocal Color Map: Yes");
  678.             DisplayLn();
  679.         }
  680.     }
  681.     else 
  682.     {
  683.         local = 0;
  684.         if (showAll) 
  685.         {
  686.             DisplayString("\pLocal Color Map: No");
  687.             DisplayLn();
  688.         }
  689.     }
  690.  
  691.     // check for the 3 zero bits 
  692.     byte2 = byte1 & 0x38;
  693.     if ( byte2 != 0 )
  694.     {
  695.         if (showAll) 
  696.         {
  697.             DisplayString("\p? -- Reserved zero bits in image not zeros.");
  698.             DisplayLn();
  699.         }
  700.     }
  701.  
  702.     // determine the # of color bits in local map 
  703.     bitsPerPix = byte1 & 0x07;
  704.     bitsPerPix++;
  705.     colors = 1 << bitsPerPix;
  706.  
  707.     if ( local == 1 ) 
  708.     {
  709.         bitsToUse = bitsPerPix;
  710.         if (showAll) 
  711.         {
  712.             DisplayString("\pBits per pixel: ");
  713.             DisplayShort(bitsPerPix, false);
  714.             DisplayString("\p Colors: ");
  715.             DisplayShort(colors, false);
  716.             DisplayLn();
  717.         }
  718.         if ( (*gPrefs)->showColors || gCmdHeldDown ) ColorMap (colorStyle, dev, colors);
  719.     }
  720.  
  721.     // retrieve the code size 
  722.     byte1 = getc(dev);
  723.     if ( (byte1 < 2) || (byte1 > 8) ) 
  724.     {
  725.         if (showAll) 
  726.         {
  727.             DisplayString("\p? -- Code size ");
  728.             DisplayLong(byte1, false);
  729.             DisplayString("\p at start of image is out of range (2-8).");
  730.             DisplayLn();            
  731.         }    
  732.     }
  733.     else
  734.     {
  735.         if (showAll) 
  736.         {
  737.             DisplayString("\pLZW min code size (bits): ");
  738.             DisplayLong(byte1, false);
  739.             DisplayLn();            
  740.         }
  741.     }
  742.     
  743.     // tally up the total bytes and read past each data block 
  744.     bytetot = 0;
  745.     possbytes = 0;
  746.  
  747.     while ( ( dataByteCount = getc(dev) ) > 0) 
  748.     {
  749.         bytetot = bytetot + dataByteCount;
  750.         for ( i = 0; (i < dataByteCount); i++ ) 
  751.         {
  752.             byte2 = getc(dev);
  753.             if ( byte2 == EOF )
  754.             {
  755.                 if ( showAll ) 
  756.                 {
  757.                     DisplayString("\p? -- EOF reached inside image data block.");
  758.                     DisplayLn();
  759.                 }
  760.                 ErrorAlert(kErrStringID, kCorruptMessage, 12915, true);
  761.             }
  762.         }
  763.     }
  764.     
  765.     possbytes = (unsigned long) width * height;
  766.     i = 8 / bitsToUse;
  767.     possbytes = possbytes / i;
  768.     if ( showAll )
  769.     {
  770.         DisplayString("\pTotal bytes: ");
  771.         DisplayLong(bytetot, false);
  772.         DisplayString("\p out of possible ");
  773.         DisplayLong(possbytes, false);
  774.         DisplayString("\p.");
  775.         DisplayLn();
  776.     }
  777.  
  778.     if ( dataByteCount == EOF ) 
  779.     {
  780.         if (showAll)
  781.         {
  782.             DisplayString("\p? -- EOF reached before zero byte count of image was read.");
  783.             DisplayLn();
  784.         }
  785.         ErrorAlert(kErrStringID, kCorruptMessage, 12916, true);
  786.     }
  787. }
  788.  
  789.  
  790.  
  791. //**********************************************************************
  792. // EXTNINFO - routine to read the GIF file for extension data and       
  793. //            display it to the screen in an orderly fasion.  This         
  794. //            extension information may be located before, between, or      
  795. //            after any of the image data.                                  
  796. //**********************************************************************
  797.  
  798. void ExtensionInfo(FILE *dev)
  799. {
  800.     int    byte1;
  801.     int    byte2;
  802.     int    i;
  803.     int    dataByteCount;
  804.  
  805.     unsigned long bytetot;
  806.  
  807.     // retrieve the function code 
  808.  
  809.     byte1 = getc(dev);
  810.     if ( showAll )
  811.     {
  812.         DisplayLn();
  813.         DisplayString("\pGIF extension seen, code : ");
  814.         DisplayLong(byte1, false);
  815.         DisplayLn();
  816.     }
  817.  
  818.     // tally up the total bytes and read past each data block 
  819.     bytetot = 0;
  820.  
  821.     while ( ( dataByteCount = getc(dev) ) > 0 ) 
  822.     {
  823.         bytetot = bytetot + dataByteCount;
  824.         for (i = 0; (i < dataByteCount); i++) 
  825.         {
  826.             byte2 = getc(dev);
  827.             if (byte2 == EOF) 
  828.             {
  829.                 if ( showAll )
  830.                 {
  831.                     DisplayString("\p? -- EOF reached inside extension data block.");
  832.                     DisplayLn();
  833.                 }
  834.                 ErrorAlert(kErrStringID, kCorruptMessage, 12917, true);
  835.             }
  836.         }
  837.     }
  838.  
  839.     if ( showAll )
  840.     {
  841.         DisplayString("\pTotal number of bytes in extension: ");
  842.         DisplayLong(bytetot, false);
  843.         DisplayLn();
  844.     }
  845.  
  846.     if (dataByteCount == EOF) 
  847.     {
  848.         if ( showAll )
  849.         {
  850.             DisplayString("\p? -- EOF was reached before zero byte count of extension was read.");
  851.             DisplayLn();
  852.         }
  853.         ErrorAlert(kErrStringID, kCorruptMessage, 12917, true);
  854.     }
  855. }
  856.  
  857.  
  858. //**********************************************************************
  859. // CHKUNEXP - routine to check for any unexpected nonzero data found    
  860. //            within the GIF file.  This routine will help determine        
  861. //            where the unexpected data may reside in the file.             
  862. //**********************************************************************
  863.  
  864. void CheckUnexpected (int *unexpected, int determiner)
  865. {
  866.     // Determine place in the GIF file 
  867.  
  868.     if ( determiner > 0 ) 
  869.     {
  870.         if ( showAll )
  871.         {
  872.             DisplayString("\p? -- ");
  873.             DisplayLong(*unexpected, false);
  874.             DisplayString("\p bytes of unexpected data found before image ");
  875.             DisplayLong(determiner, false);
  876.             DisplayString("\p.");
  877.             DisplayLn();
  878.         }
  879.     }
  880.     else if ( determiner == -1 ) 
  881.     {
  882.         if ( showAll )
  883.         {
  884.             DisplayString("\p? -- ");
  885.             DisplayLong(*unexpected, false);
  886.             DisplayString("\p bytes of unexpected data found before GIF file terminator.");
  887.             DisplayLn();
  888.         }
  889.     }
  890.     else 
  891.     {
  892.         if ( showAll )
  893.         {
  894.             DisplayString("\p? -- ");
  895.             DisplayLong(*unexpected, false);
  896.             DisplayString("\p bytes of unexpected data found after GIF file terminator.");
  897.             DisplayLn();
  898.         }
  899.     }
  900.  
  901.     // Zero out unexpected variable for next group that may be encountered 
  902.     *unexpected = 0;
  903. }
  904.  
  905. /************************************************************************
  906.     Name and address of the original author (1989!!):
  907.  
  908.     jdm@hodge.cts.com [uunet zardoz vdelta crash]!hodge!jdm
  909.  
  910.     James D. Murray, Ethnounixologist
  911.     Hodge Computer Research Corporation
  912.     1588 North Batavia Street 
  913.     Orange, California 92667  USA
  914.  
  915.     TEL: (714) 998-7750    Ask for James
  916.     FAX: (714) 921-8038    Wait for the carrier
  917. ************************************************************************/
  918.